import pandas as pd
import random
import re
import math
from PIL import Image
from openpyxl.drawing.image import Image
from openpyxl.drawing.spreadsheet_drawing import AnchorMarker, OneCellAnchor
from openpyxl.drawing.xdr import XDRPositiveSize2D
from openpyxl.styles import Font, Alignment
from openpyxl.utils.units import pixels_to_EMU
import copy
import openpyxl
from openpyxl.utils import column_index_from_string as Col2Int
from concurrent.futures import ThreadPoolExecutor
from urls import TEMPLATES
import xlwings
def judge_part(items, part):
    pattern = '|'.join(str(x) for x in items)
    if len(re.findall(pattern, part)) > 0:
        return True
    else:
        return False


class ProjectInformationBase:

    # 基础信息
    def __init__(self) -> None:
        self.config = {
            '项目名称': '武义桃花源房地产开发项目 （二期）--二标段 ',
            '单位工程': '',
            '分部工程': '主体结构',
            '项目负责人': '李凤山',
            '施工单位': '海天建设集团有限公司',
            '监理单位': '浙江万基工程管理有限公司',
            '分包单位': '/',
            '分包单位项目负责人': '/',
            '检验批部位': 'D11#楼B-14~B-28/B-A~B-L轴三层结构梁板梯',
            '常规': True
        }

        self.muban_config = {
            '后浇带': 15,
            '梁': 13,
            '板': 23,
            '柱': 13,
            '墙': 14,
            '楼梯': 3,
            '预制构件': 24,
            '其他': 0
        }


class ProjectInformationWood(ProjectInformationBase):
    # 模板数据的格式的整理和梳理
    config_item = ['后浇带', '梁', '板', '柱', '墙', '楼梯', '预制构件']
    config_unit = {'后浇带': '处', '梁': '件', '板': '间', '柱': '件', '墙': '间', '楼梯': '跑', '预制构件': '件'}

    def __init__(self):
        super().__init__()

        self.check_number_func = {

            '梁检查数量': math.ceil(self.muban_config['梁'] / 10),
            '板检查数量': math.ceil(self.muban_config['板'] / 10),
            '柱检查数量': math.ceil(self.muban_config['柱'] / 10),
            '墙检查数量': math.ceil(self.muban_config['墙'] / 10),
            '楼梯检查数量': self.muban_config['楼梯'],
            '预制构件检查数量': math.ceil(self.muban_config['墙'] / 10),
            '后浇带检查数量': self.muban_config['后浇带'],
        }

        self.check_number_func['构件总数'] = sum(list(self.check_number_func.values()))


class ProjectInFoErrorRelex(object):

    # 错误处理的类

    def __init__(self, number: int, OldRange: list[int], accuracy=90):
        """

        @param number: 需要检查的数量
        @param OldRange: 检查的氛围
        @param accuracy: 正确率
        """

        self.true_numer = None
        self.error_name = None
        self.DateFrame = None
        self.number = number

        self.OldRange = OldRange
        self.accuracy = accuracy
        self.rowdata = {}
        self.run()

    def run(self):
        ##1、获取正确和错误的个数
        self.true_numer, self.error_name = self.True_and_error(self.number)
        list1 = [self.error_number(self.OldRange) for _ in range(self.error_name)]  # 根据错误的数据范围生成数据
        list2 = [random.randint(*self.OldRange) for _ in range(self.true_numer)]
        list3 = list(list1 + list2)
        # 2、生成序号
        numbers = [x for x in range(int(len(list3)))]
        random.shuffle(numbers)
        self.DateFrame = pd.DataFrame({'位置': numbers, '数据': list3})
        if self.error_name == 0:
            self.rowdata['错误数据所在的位置'] = 0
        else:
            self.rowdata['错误数据所在的位置'] = self.DateFrame['位置'].iloc[:self.error_name].to_list()  # 错误数据所在的位置

        self.rowdata['数据'] = self.DateFrame.sort_values(by=['位置'])['数据'].to_list()

        if self.rowdata['错误数据所在的位置'] != 0:
            for value in self.rowdata['错误数据所在的位置']:
                if self.OldRange[0] <= self.rowdata['数据'][value] <= self.OldRange[1]:
                    self.rowdata['错误数据所在的位置'].remove(value)

        # print(self.rowdata)

    def error_number(self, size):

        new_size = {}
        args = random.randint(65, 100) / 100
        if size[0] < 0:

            new_size[0] = int(size[0] / args)
        else:
            new_size[0] = int(size[0] * args)

        if size[1] < 0:

            new_size[1] = int(size[1] * args)
        else:
            new_size[1] = int(size[1] * (1 + args))

        size = {
            '下限生成': [new_size[0], size[0]],
            '上限生成': [size[1], new_size[1]]
        }
        if self.OldRange[0] == 0 or self.OldRange[1] == 0:
            if self.OldRange[0] == 0:
                return random.randint(*size['上限生成'])

            if self.OldRange[1] == 1:
                return random.randint(*size['下限生成'])

        if random.random() > 0.5:

            return random.randint(*size['下限生成'])
        else:
            return random.randint(*size['上限生成'])

    @staticmethod
    def __inquire__image__(sheet, imagepath=None, imagesheape=None,
                           row=None, col=None, rowOff=0, colOff=0):
        """把图片插入到excel文件中的指定位置
        插入到指定单元格然后向右偏移一点距离，目的是不让图片的边框和单元格的边框重合
        :param sheet:工作表名称
        :param row：起始单元格行号
        :param col:起始单元格列号
        :param rowOff：行偏移距离（10000为单位）
        :param colOff：列偏移距离（10000为单位）
        :return:
        """
        if imagepath is None:
            from urls import TEMPLATES
            imagepath = TEMPLATES['static']['error_image']
        if imagesheape is None:
            imagesheape = [25, 25]
        if rowOff is None:
            rowOff = 0
        if colOff is None:
            colOff = 0

        img = Image(imagepath)
        # 设置图片的宽和高
        img.width, img.height = imagesheape

        """精确设置图片位置，偏移量以万为单位进行微调吧，具体计算公式太麻烦了
        row column 的索引都是从0开始的,我这里要把图片插入到单元格B10
        """
        p2e = pixels_to_EMU
        h, w = img.height, img.width
        size = XDRPositiveSize2D(p2e(w), p2e(h))
        marker = AnchorMarker(
            col=int(col) - 1,
            colOff=colOff,
            row=int(row) - 1,
            rowOff=rowOff)
        img.anchor = OneCellAnchor(_from=marker, ext=size)

        # 将图片添加到excel中
        sheet.add_image(img)
        print('图片插入成功')

    def True_and_error(self, number):

        bili = random.randint(self.accuracy, 100) / 100
        if number <= 3:
            true_numer = 3
            error_name = 0
            return [true_numer, error_name]
        true_numer = int(random.randint(int(number * bili), number))  # 正确的个数

        error_name = int(number - true_numer)  # 错误的个数

        return [true_numer, error_name]

    def __str__(self):

        return (f'正确的个数{self.true_numer};'
                f'错误的个数{self.error_name};'
                f'正确的数据{self.rowdata["数据"]};'
                f'范围{self.OldRange};'
                f'错误数据所在的位置{self.rowdata["错误数据所在的位置"]};')


class ProjectInFoDataFrame(ProjectInformationBase):

    def __init__(self):
        super().__init__()
        excel_path = r'./Templates/模板/模板数据.xlsx'
        self.excel_path = excel_path

        self.Dataframe = pd.read_excel(self.excel_path, header=0)
        # print(self.Dataframe)
        self.Dataframe['检验批部位'] = self.config['检验批部位']

        self.Dataframe['是否需要'] = self.Dataframe['规则1'].apply(
            lambda series: eval(series)(ProjectInformationBase().config))

        self.Dataframe['检查数量'] = self.Dataframe['规则2'].apply(
            lambda series: ProjectInformationWood().check_number_func[series])

        self.Dataframe['范围'] = self.Dataframe['范围'].apply(lambda x: eval(x))

        self.Dataframe['所有的数据'] = self.Dataframe[['范围', '检查数量']].apply(
            lambda x: ProjectInFoErrorRelex(number=x['检查数量'], OldRange=x['范围'], accuracy=90).rowdata, axis=1)

        self.Dataframe['数据'] = self.Dataframe['所有的数据'].apply(lambda x: x['数据'])

        self.Dataframe['错误数据所在的位置'] = self.Dataframe['所有的数据'].apply(lambda x: x['错误数据所在的位置'])

        self.Dataframe['起始列号'] = self.Dataframe['行号'].apply(lambda x: Col2Int(re.findall('[A-Z]+', x)[0]))

        self.Dataframe['起始行号'] = self.Dataframe['行号'].apply(lambda x: re.findall('[0-9]+', x)[0])

        self.Dataframe['新的数据'] = self.Dataframe[['数据', '起始列号', '起始行号']].apply(
            lambda Series: [[value,
                             [math.ceil((key + 1) / 10),
                              Series['起始行号'],
                              Series['起始列号'] + key - (math.ceil((key + 1) / 10) - 1) * 10]]
                            for key, value in enumerate(Series['数据'])], axis=1)
        self.fillydataframe = self.Dataframe.copy()
        self.fillydataframe['最终数据'] = self.Dataframe[['新的数据', '错误数据所在的位置']].apply(
            lambda x: self.__boolFalse__(Series1=x['新的数据'], Series2=x['错误数据所在的位置']), axis=1)

    def __boolFalse__(self, Series1: list, Series2: list):
        """_summary_
        Args:
            Series1 (list): 所有的数据
            Series2 (list): 错误数据所在的位置
        """
        if type(Series2) is list:
            for key, value in enumerate(Series1):
                if key in Series2:
                    Series1[key].append(False)
                else:
                    Series1[key].append(True)
            return Series1
        else:
            for item in Series1:
                item.append(True)
            return Series1


# class MuBan(ProjectInFoDataFrame):

#     def __init__(self):
#         super().__init__()

#         """
#         @param excel_path2: 路径
#         @param Dataframe: 【内容,[页码,行号,列号]】
#         @param passage:需要处理的页码
#         """
#         excel_path2 =TEMPLATES['模板']['模板安装']

#         self.dirdataframe = self.fillydataframe
#         self.pasages = self.dirdataframe['页码'].unique()

#         self.WorkBook = openpyxl.load_workbook(excel_path2)

#         self.all_sheet_names = self.WorkBook.sheetnames.copy()  # 所有的工作簿名称的集合
#         self.max_pasge =[]#获取最大的页数范围
#         # 主要程序入口
#         for pasge in self.pasages:


#             self.Dataframe = self.dirdataframe[
#                 (self.dirdataframe['页码'] == pasge) & (self.dirdataframe['是否需要'] == True)]
#             try:
#                 max_pasge = math.ceil(self.Dataframe['检查数量'].max() / 10)
#                 self.max_pasge.append(max_pasge)

#                 all_sheet_names = []
#                 print('最大页码：', max_pasge)
#                 # self.passage = pasge
#                 # 生成需要写入的页码
#                 sheet = self.WorkBook[self.WorkBook.sheetnames[pasge]]  # 这里就是页码

#                 # 开始处理该页面的数据
#                 self.Pasge(sheet, pasge, max_pasge, all_sheet_names)
#                 # 删除当前页
#                 self.all_sheet_names.remove(self.WorkBook.sheetnames[pasge])
#                 self.WorkBook.remove(sheet)

#             except:
#                 print(f'第{pasge}页没有数据')
#                 print(self.WorkBook.sheetnames[pasge - 1])
#                 self.WorkBook.move_sheet(self.WorkBook.sheetnames[pasge - 1], sum(self.max_pasge))

#         """ 全局函数写入的部位 """
#         # print(self.all_sheet_names)
#         dirsheets=self.WorkBook.sheetnames[1:]
#         print('开始写入', dirsheets)
        
#         """ 这里开始写入抬头页码 """
#         """ 每页写的位置需要固定 """
#         for index,sheetname in enumerate(dirsheets):
#             self.WorkBook[sheetname]['W3']=len(dirsheets)
#             self.WorkBook[sheetname]['Z3']=index+1

#         self.WorkBook.save('./122222222222222222.xlsx')
#         print('完成')
#         self.WorkBook.close()

#     def Pasge(self, dirsheet, pasge, max_pasge, all_sheet_names):

#         for x in range(max_pasge):
#             new_sheet = self.WorkBook.copy_worksheet(dirsheet)
#             new_sheet.title = f'{self.WorkBook.sheetnames[pasge]}-{x + 1}'
#             all_sheet_names.append(new_sheet.title)
#             self.all_sheet_names.append(new_sheet.title)

#         dirlist = self.Dataframe['最终数据'].shape[0]
#         # 横向少量规范对应写入

#         # 横向多列数据写入
#         for index in range(dirlist):
#             # print('行号:', index)
#             self.__write_excel__(index, all_sheet_names)

#     def __write_excel__(self, index, all_sheet_names):

#         # 主要写入excel的核心的核心部件

#         # [[1, [1, '9', 12]], [4, [1, '9', 13]], [2, [1, '9', 14]]]
#         for data in self.Dataframe['最终数据'].iloc[index]:
#             value, item, bool = data
#             Page1, row, col = item
#             # 1 、写入部位
#             firstname = all_sheet_names[Page1 - 1]
#             DirSheet = self.WorkBook[firstname]
#             DirSheet[self.Dataframe['行号'].iloc[index]] = self.Dataframe['检验批部位'].iloc[index]
#             DirSheet[self.Dataframe['行号'].iloc[index]].font = Font(size=6)
#             DirSheet[self.Dataframe['行号'].iloc[index]].alignment = Alignment(horizontal='center',
#                                                                                vertical='center',
#                                                                                wrap_text=True)
#             # 2 、写入检查部位
#             dirrow = int(row)
#             dircol = int(col) + 4

#             DirSheet.cell(row=dirrow, column=dircol).value = value

#             # 3 、插入错误图片
#             print(bool)
#             if bool is False:
#                 print('需要插入图片')
#                 ProjectInFoErrorRelex.__inquire__image__(DirSheet, row=dirrow, col=dircol, colOff=5000, rowOff=50000)
#                 print('插入完毕')


class MuBan(object):

    def __init__(self):

        """ 基础配置关闭软件打开和自动刷新"""
        app = xlwings.App(visible=True, add_book=False)
        app.display_alerts = False    # 关闭一些提示信息，可以加快运行速度。 默认为 True。
        app.screen_updating = True    # 更新显示工作表的内容。默认为 True。关闭它也可以提升运行速度。


        """ 1、现根据最大页数复制工作表把 """

        excel_path2 =TEMPLATES['模板']['模板安装']

        wb = app.books.open(excel_path2)  
        







def main():
    dirdataframe = ProjectInFoDataFrame().fillydataframe
    pasages = dirdataframe['页码'].unique()
    for pasge in pasages:
        newdataframe = dirdataframe[(dirdataframe['页码'] == pasge) & (dirdataframe['是否需要'] == True)]
        max_pasge = math.ceil(newdataframe['检查数量'].max() / 10)
        # print(newdataframe)
        # newdataframe.to_csv('1.csv')
        # print(newdataframe.index.to_list())
        MuBan()
        break


if __name__ == '__main__':
    main()
